/**
 * @file      : list.c
 * @brief     : 链表源文件
 * @author    : huenrong (huenrong1028@gmail.com)
 * @date      : 2020-09-06 15:03:63
 *
 * @copyright : Copyright (c) 2020  胡恩荣
 *
 */

#include "./list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * @brief  初始化链表(创建一个头节点)
 * @param  list: 输出参数, 创建的链表
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @return 成功: 0
 *         失败: -1
 */
int init_list(struct list_node *list,
              pthread_mutex_t *list_mutex)
{
    struct list_node *head = NULL;

    // 创建一个头节点
    // 第0个节点, 不存放数据
    head = (struct list_node *)malloc(sizeof(struct list_node));
    if (NULL == head)
    {
        return -1;
    }

    memset(head, 0, sizeof(struct list_node));

    pthread_mutex_init(list_mutex, NULL);

    list = head;

    return 0;
}

/**
 * @brief  在链表头部插入数据
 * @param  list_mutex : 输出参数, 链表互斥锁
 * @param  list       : 输出参数, 需要插入数据的链表
 * @param  insert_data: 输入参数, 待插入数据
 * @return 成功: 0
 *         失败: -1
 */
int insert_head_list(pthread_mutex_t *list_mutex,
                     struct list_node *list,
                     const element_type insert_data)
{
    // 待插入的节点
    struct list_node *insert_node = NULL;

    pthread_mutex_lock(list_mutex);

    // 创建新节点
    insert_node = (struct list_node *)malloc(sizeof(struct list_node));
    if (NULL == insert_node)
    {
        pthread_mutex_unlock(list_mutex);

        return -1;
    }

    memset(insert_node, 0, sizeof(struct list_node));

    // 新节点数据域赋值
    memcpy(&(insert_node->data), &insert_data, sizeof(element_type));

    // 新节点地址域, 指向原链表的第一个节点
    insert_node->next = list->next;

    // 新链表指向新节点
    list->next = insert_node;

    pthread_mutex_unlock(list_mutex);

    return 0;
}

/**
 * @brief  在链表尾部插入数据
 * @param  list_mutex : 输出参数, 链表互斥锁
 * @param  list       : 输入参数, 需要插入数据的链表
 * @param  insert_data: 输入参数, 待插入数据
 * @return 成功: 0
 *         失败: -1
 */
int insert_tail_list(pthread_mutex_t *list_mutex,
                     const struct list_node *list,
                     const element_type insert_data)
{
    // 临时链表节点
    struct list_node *tmp_node = NULL;
    // 待插入的节点
    struct list_node *insert_node = NULL;

    pthread_mutex_lock(list_mutex);

    // 创建新节点
    insert_node = (struct list_node *)malloc(sizeof(struct list_node));
    if (NULL == insert_node)
    {
        pthread_mutex_unlock(list_mutex);

        return -1;
    }

    memset(insert_node, 0, sizeof(struct list_node));

    // 新节点数据域赋值
    memcpy(&(insert_node->data), &insert_data, sizeof(element_type));

    // 新节点地址域指向NULL(尾节点)
    insert_node->next = NULL;

    tmp_node = (struct list_node *)list;

    // 寻找链表尾
    while (NULL != tmp_node->next)
    {
        tmp_node = tmp_node->next;
    }

    // 原尾节点指向新插入的节点
    tmp_node->next = insert_node;

    pthread_mutex_unlock(list_mutex);

    return 0;
}

/**
 * @brief  查找指定数据的节点(查找到第一个就返回)
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @param  list      : 输入参数, 待查找的链表
 * @param  node_data : 输入参数, 待查找的节点数据
 * @return 成功: 查找到的节点信息
 *         失败: NULL
 */
struct list_node *find_node_list(pthread_mutex_t *list_mutex,
                                 const struct list_node *list,
                                 const element_type node_data)
{
    // 临时链表节点
    struct list_node *tmp_node = NULL;

    pthread_mutex_lock(list_mutex);

    tmp_node = (struct list_node *)list;

    while ((NULL != tmp_node) &&
           (0 != memcmp(&node_data, &(tmp_node->data), sizeof(element_type))))
    {
        tmp_node = tmp_node->next;
    }

    pthread_mutex_unlock(list_mutex);

    return tmp_node;
}

/**
 * @brief  查找指定数据的前一个节点(查找到第一个就返回)
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @param  list      : 输入参数, 待查找的链表
 * @param  node_data : 输入参数, 待查找的节点数据
 * @return 成功: 查找到的节点信息
 *         失败: NULL
 */
struct list_node *find_previous_node_list(pthread_mutex_t *list_mutex,
                                          const struct list_node *list,
                                          const element_type node_data)
{
    // 临时链表节点
    struct list_node *tmp_node = NULL;

    pthread_mutex_lock(list_mutex);

    tmp_node = (struct list_node *)list;

    while ((NULL != tmp_node->next) &&
           (0 != memcmp(&node_data,
                        &(tmp_node->next->data),
                        sizeof(element_type))))
    {
        tmp_node = tmp_node->next;
    }

    pthread_mutex_unlock(list_mutex);

    return tmp_node;
}

/**
 * @brief  从链表中删除指定数据节点(只删除符合要求的第一个节点)
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @param  list      : 输入参数, 待删除节点的链表
 * @param  node_data : 输入参数, 待删除节点的数据
 */
void delete_node_list(pthread_mutex_t *list_mutex,
                      const struct list_node *list,
                      const element_type node_data)
{
    // 待删除节点的上一个节点
    struct list_node *previous_node = NULL;
    // 待删除节点
    struct list_node *delete_node = NULL;

    // 查找待删除节点的上一个节点
    previous_node = find_previous_node_list(list_mutex, list, node_data);

    pthread_mutex_lock(list_mutex);

    // 记录待删除节点的信息
    delete_node = previous_node->next;

    // 更改上一个节点的指向
    previous_node->next = delete_node->next;

    // 释放待删除节点
    free(delete_node);

    pthread_mutex_unlock(list_mutex);
}

/**
 * @brief  判断链表是否为空
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @param  list: 输入参数, 待判断的链表
 * @return 链表为空: 0
 *         链表非空: -1
 */
int is_empty_list(pthread_mutex_t *list_mutex,
                  const struct list_node *list)
{
    pthread_mutex_lock(list_mutex);

    if (NULL == list->next)
    {
        pthread_mutex_unlock(list_mutex);

        return 0;
    }

    pthread_mutex_unlock(list_mutex);

    return -1;
}

/**
 * @brief  获取链表长度(包括首节点)
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @param  list      : 输入参数, 待判断的链表
 * @return 链表长度
 */
int get_list_len(pthread_mutex_t *list_mutex,
                 const struct list_node *list)
{
    // 链表长度
    uint32_t len = 0;
    // 临时链表节点
    struct list_node *tmp_node = NULL;

    pthread_mutex_lock(list_mutex);

    tmp_node = (struct list_node *)list;

    while (NULL != tmp_node)
    {
        len++;
        tmp_node = tmp_node->next;
    }

    pthread_mutex_unlock(list_mutex);

    return len;
}

/**
 * @brief  删除链表(头节点也会删除)
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @param  list      : 输出参数, 待删除的链表
 */
void delete_list(pthread_mutex_t *list_mutex,
                 struct list_node *list)
{
    // 临时节点
    struct list_node *tmp_node = NULL;
    // 待删除节点
    struct list_node *delete_node = NULL;

    pthread_mutex_lock(list_mutex);

    // 删除头节点
    delete_node = list->next;
    list->next = NULL;

    // 循环删除后面节点
    while (NULL != delete_node)
    {
        tmp_node = delete_node->next;

        free(delete_node);

        delete_node = tmp_node;
    }

    pthread_mutex_unlock(list_mutex);
}

/**
 * @brief  遍历链表(需要根据实际情况修改)
 * @param  list_mutex: 输出参数, 链表互斥锁
 * @param  list      : 输入参数, 待遍历链表
 */
void traverse_list(pthread_mutex_t *list_mutex,
                   const struct list_node *list)
{
    // 临时节点
    struct list_node *tmp_node = NULL;

    pthread_mutex_lock(list_mutex);

    // 跳过首节点
    tmp_node = list->next;

    while (NULL != tmp_node)
    {
        printf("[id = %d, time = %d]\n",
               (tmp_node->data.id), (tmp_node->data).time);

        tmp_node = tmp_node->next;
    }

    printf("\n");

    pthread_mutex_unlock(list_mutex);
}
